#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <SPI.h>
WiFiClient espClient;
ESP8266WiFiMulti wifiMulti;
const uint32_t connectTimeoutMs = 10000;
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

//IO settings
int BUSY_Pin = D2;  //4
int RES_Pin = D4;   //2
int DC_Pin = D3;    //0
int CS_Pin = D8;    //15
int SCK_Pin = D5;   //14
int SDI_Pin = D7;   //13
const char* ss;
#define EPD_W21_MOSI_0  digitalWrite(SDI_Pin,LOW)
#define EPD_W21_MOSI_1  digitalWrite(SDI_Pin,HIGH) 
#define EPD_W21_CLK_0 digitalWrite(SCK_Pin,LOW)
#define EPD_W21_CLK_1 digitalWrite(SCK_Pin,HIGH)
#define EPD_W21_CS_0 digitalWrite(CS_Pin,LOW)
#define EPD_W21_CS_1 digitalWrite(CS_Pin,HIGH)
#define EPD_W21_DC_0  digitalWrite(DC_Pin,LOW)
#define EPD_W21_DC_1  digitalWrite(DC_Pin,HIGH)
#define EPD_W21_RST_0 digitalWrite(RES_Pin,LOW)
#define EPD_W21_RST_1 digitalWrite(RES_Pin,HIGH)
#define isEPD_W21_BUSY digitalRead(BUSY_Pin)
//400*300///////////////////////////////////////
#define MONOMSB_MODE 1
#define MONOLSB_MODE 2 
#define RED_MODE     3
#define MAX_LINE_BYTES   50//=400/8
#define MAX_COLUMN_BYTES  300
#define ALLSCREEN_GRAGHBYTES  15000
////////FUNCTION//////
void driver_delay_us(unsigned int xus);
void driver_delay_xms(unsigned long xms);
void DELAY_S(unsigned int delaytime);     
void SPI_Delay(unsigned char xrate);
void SPI_Write(unsigned char value);
void Epaper_Write_Command(unsigned char command);
void Epaper_Write_Data(unsigned char command);
//EPD
void Epaper_READBUSY(void);
void Epaper_Spi_WriteByte(unsigned char TxData);
void Epaper_Write_Command(unsigned char cmd);
void Epaper_Write_Data(unsigned char data);

void EPD_HW_Init(void); //Electronic paper initialization
void EPD_Update(void);
void EPD_DeepSleep(void);
//Display 
void EPD_WhiteScreen_ALL(unsigned char *BW_datas,unsigned char *R_datas);
void EPD_WhiteScreen_ALL_x(unsigned char *BW_datas,unsigned char *R_datas);
void EPD_WhiteScreen_ALL_Clean(void);
void EPD_WriteText(unsigned char *image,unsigned char *text);

void setup() {
   pinMode(BUSY_Pin, INPUT); 
   pinMode(RES_Pin, OUTPUT);  
   pinMode(DC_Pin, OUTPUT);    
   pinMode(CS_Pin, OUTPUT);    
   pinMode(SCK_Pin, OUTPUT);    
   pinMode(SDI_Pin, OUTPUT);    
   Serial.begin(115200);
   SPI.begin();
   SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
   //SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
  WiFi.persistent(false);
  // Set WiFi to station mode
  WiFi.mode(WIFI_STA);
  // Register multi WiFi networks
  wifiMulti.addAP("SSID", "PASS");

  
    Serial.print("WiFi start");
    setup_wifi();
}
 
void loop() {
  EPD_HW_Init(); //Electronic paper initialization
  if(check_http()){
    getfromhttp_black();
    getfromhttp_red();
    EPD_Update(); 
    EPD_DeepSleep();
  }
  ESP.deepSleep(3200e6);
}

bool check_http(){
    WiFiClient client;
    HTTPClient http;
    int len=0;
    if (http.begin(client, "http://8266.ghoot.com:8800/black")) {  // HTTP
      Serial.print("[HTTP] GET...\n");
      // start connection and send HTTP header
      int httpCode = http.GET();
      // httpCode will be negative on error
      if (httpCode == 200 || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          len = http.getSize();
      }
    }
    Serial.print(len);
    if(len==30000){
      return true;
    }else{
      return false;
    }
}

void setup_wifi() {
    Serial.print("WiFi connect ");
    while(wifiMulti.run(connectTimeoutMs) != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
    Serial.print("WiFi connected: ");
    Serial.print(WiFi.SSID());
    Serial.print(" ");
    Serial.println(WiFi.localIP());

  delay(1000);
}


void EPD_WriteText(unsigned char *image,unsigned char *text){
    Serial.printf("start");
  for(int i=0;i<1000;i++){
    Serial.printf("writetext");
    image[i]=0xff;
  }
}

///////////////////EXTERNAL FUNCTION////////////////////////////////////////////////////////////////////////
/////////////////////delay//////////////////////////////////////
void driver_delay_us(unsigned int xus)  //1us
{
  for(;xus>1;xus--);
}
void driver_delay_xms(unsigned long xms) //1ms
{  
    unsigned long i = 0 , j=0;

    for(j=0;j<xms;j++)
  {
        for(i=0; i<256; i++);
    }
}
void DELAY_S(unsigned int delaytime)     
{
  int i,j,k;
  for(i=0;i<delaytime;i++)
  {
    for(j=0;j<4000;j++)           
    {
      for(k=0;k<222;k++);
                
    }
  }
}
//////////////////////SPI///////////////////////////////////
void SPI_Delay(unsigned char xrate)
{
  unsigned char i;
  while(xrate)
  {
    for(i=0;i<2;i++);
    xrate--;
  }
}

void SPI_Write(unsigned char value)                                    
{          
  SPI.transfer(value);                 
}

void Epaper_Write_Command(unsigned char command)
{
  SPI_Delay(1);
  EPD_W21_CS_0;                   
  EPD_W21_DC_0;   // command write
  SPI_Write(command);
  EPD_W21_CS_1;
}
void Epaper_Write_Data(unsigned char command)
{
  SPI_Delay(1);
  EPD_W21_CS_0;                   
  EPD_W21_DC_1;   // command write
  SPI_Write(command);
  EPD_W21_CS_1;
}

/////////////////EPD settings Functions/////////////////////
void EPD_HW_Init(void)
{
    EPD_W21_RST_0;  // Module reset      
    delay(1); //At least 10ms delay 
    EPD_W21_RST_1; 
    delay(1); //At least 10ms delay   
    
    Epaper_READBUSY();    //waiting for the electronic paper IC to release the idle signal
    Epaper_Write_Command(0x12);     //SWRESET
    Epaper_READBUSY();  //waiting for the electronic paper IC to release the idle signal
  
    Epaper_Write_Command(0x74);
    Epaper_Write_Data(0x54);
    Epaper_Write_Command(0x7E);
    Epaper_Write_Data(0x3B);
    Epaper_Write_Command(0x2B);  // Reduce glitch under ACVCOM  
    Epaper_Write_Data(0x04);           
    Epaper_Write_Data(0x63);

    Epaper_Write_Command(0x0C);  // Soft start setting
    Epaper_Write_Data(0x8B);           
    Epaper_Write_Data(0x9C);
    Epaper_Write_Data(0x96);
    Epaper_Write_Data(0x0F);

    Epaper_Write_Command(0x01);  // Set MUX as 300
    Epaper_Write_Data(0x2B);           
    Epaper_Write_Data(0x01);
    Epaper_Write_Data(0x00);     

    Epaper_Write_Command(0x11);  // Data entry mode
    Epaper_Write_Data(0x03);         
    Epaper_Write_Command(0x44); 
    Epaper_Write_Data(0x00); // RAM x address start at 0
    Epaper_Write_Data(0x31); // RAM x address end at 31h(49+1)*8->400
    Epaper_Write_Command(0x45); 
    Epaper_Write_Data(0x00); // RAM y address end at 00h     
    Epaper_Write_Data(0x00);
    Epaper_Write_Data(0x2B);   // RAM y address start at 12Bh     
    Epaper_Write_Data(0x01);
    Epaper_Write_Command(0x3C); // board
    Epaper_Write_Data(0x01); // HIZ
    Epaper_Write_Command(0x18);
    Epaper_Write_Data(0X80);
    Epaper_Write_Command(0x22);
    Epaper_Write_Data(0XB1);  //Load Temperature and waveform setting.
    Epaper_Write_Command(0x20);
    Epaper_READBUSY();    //waiting for the electronic paper IC to release the idle signal
    

    Epaper_Write_Command(0x4E); 
    Epaper_Write_Data(0x00);
    Epaper_Write_Command(0x4F); 
    Epaper_Write_Data(0x00);
    Epaper_Write_Data(0x00);
}

void EPD_HW_Init_1(void)
{

}
//////////////////////////////All screen update////////////////////////////////////////////
void EPD_WhiteScreen_ALL(unsigned char *BW_datas,unsigned char *R_datas)
{
   unsigned int i;  
  Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {     
    //ss=(char*)i;          
    //Serial.printf("a\n");
     Epaper_Write_Data(pgm_read_byte(&BW_datas[i]));
   }
  Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {               
     Epaper_Write_Data(~pgm_read_byte(&R_datas[i]));
   }
   EPD_Update();   
}

void EPD_WhiteScreen_ALL_x(unsigned char *BW_datas,unsigned char *R_datas)
{
   unsigned int i,j;  
  Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
   for(j=299;j>0;j--){
      for(i=0;i<50;i++){
        Epaper_Write_Data(pgm_read_byte(&BW_datas[(j*50)+i]));
      }
   }
  Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
  
   for(j=299;j>0;j--){
      for(i=0;i<50;i++){
        Epaper_Write_Data(~pgm_read_byte(&R_datas[(j*50)+i]));
      }
   }
   EPD_Update();   
}

/////////////////////////////////////////////////////////////////////////////////////////
void EPD_Update(void)
{   
  
  Epaper_Write_Command(0x22); //Display Update Control
  Epaper_Write_Data(0xC7);   
  Serial.printf("eeee");
  Epaper_Write_Command(0x20);  //Activate Display Update Sequence
  Serial.printf("cccc");
  delay(30);
  Serial.printf("dddd");
  Epaper_READBUSY();   

}

void EPD_UpdatePart(void)
{   
  
  Epaper_Write_Command(0x22); //Display Update Control
  Epaper_Write_Data(0x0C);   
  Serial.printf("eeee");
  Epaper_Write_Command(0x20);  //Activate Display Update Sequence
  Serial.printf("cccc");
  delay(30);
  Serial.printf("dddd");
  Epaper_READBUSY();   

}

void EPD_DeepSleep(void)
{  
  Epaper_Write_Command(0x10); //enter deep sleep
  Epaper_Write_Data(0x01); 
  delay(100);
}
void Epaper_READBUSY(void)
{ 
  while(isEPD_W21_BUSY!=0)
  {   
    ESP.wdtFeed();
  }  
}

void EPD_WhiteScreen_ALL_Clean(void)
{
   unsigned int i;  
  Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {        
     Epaper_Write_Data(0xff);
   }
  Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {              
     Epaper_Write_Data(0x00);
   }
   EPD_Update();   
}

void part_test(void)
{
    Epaper_Write_Command(0x44); 
    Epaper_Write_Data(0x0c); // RAM x address start at 0
    Epaper_Write_Data(0x24); // RAM x address end at 31h(49+1)*8->400
    Epaper_Write_Command(0x45); 
    Epaper_Write_Data(0xde); // RAM y address end at 00h     
    Epaper_Write_Data(0x00);
    Epaper_Write_Data(0x4a);   // RAM y address start at 12Bh     
    Epaper_Write_Data(0x00);
    
    Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
    unsigned int i; 
   for(i=0;i<3750;i++)
   {        
     Epaper_Write_Data(0xff);
   }
   EPD_UpdatePart();
}
int split(char dst[][80], char* str, const char* spl)
{
    int n = 0;
    char *result = NULL;
    result = strtok(str, spl);
    while( result != NULL )
    {
        strcpy(dst[n++], result);
        result = strtok(NULL, spl);
    }
    return n;
}
auto getNum = [](char c)
{
  return c > '9' ? c - 'a' + 10 : c - '0';
};
void getfromhttp_black(){
    WiFiClient client;

    HTTPClient http;

    Serial.print("[HTTP] begin...\n");
    if (http.begin(client, "http://8266.ghoot.com:8800/black")) {  // HTTP
      Serial.print("[HTTP] GET...\n");
      // start connection and send HTTP header
      int httpCode = http.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);

        // file found at server
      if (httpCode == 200 || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          int len = http.getSize();
          
          Serial.println(len);
          // create buffer for read
          uint8_t buff[128] = { 0 };
          // get tcp stream
          WiFiClient * stream = &client;
          // read all data from server
          EPD_HW_Init(); //Electronic paper initialization
          Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
          while (http.connected() && (len > 0 || len == -1)) {
            // read up to 128 byte
            int c = stream->readBytes(buff, std::min((size_t)len, sizeof(buff)));
            //Serial.printf("readBytes: %d\n", c);
            if (!c) {
              Serial.println("read timeout");
            }
            // write it to Serial
            //Serial.write(buff, c);
             unsigned int i; 
             int dh, dl;  // 16进制的高4位和低4位  
             unsigned char dest; 
             for(i=0;i<128;i=i+2)
             {        
              dest=(getNum(buff[i]) << 4) + getNum(buff[i+1]);
              Epaper_Write_Data(dest);
             }
            if (len > 0) {
              len -= c;
            }
          }
          
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }

      http.end();
    } else {
      Serial.printf("[HTTP} Unable to connect\n");
    }
  }
}
void getfromhttp_red(){
    WiFiClient client;

    HTTPClient http;

    Serial.print("[HTTP] begin...\n");
    if (http.begin(client, "http://8266.ghoot.com:8800/red")) {  // HTTP
      Serial.print("[HTTP] GET...\n");
      // start connection and send HTTP header
      int httpCode = http.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);

        // file found at server
      if (httpCode == 200 || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          int len = http.getSize();
          
          Serial.println(len);
          // create buffer for read
          uint8_t buff[128] = { 0 };
          // get tcp stream
          WiFiClient * stream = &client;
          // read all data from server
          EPD_HW_Init(); //Electronic paper initialization
          Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
          while (http.connected() && (len > 0 || len == -1)) {
            // read up to 128 byte
            int c = stream->readBytes(buff, std::min((size_t)len, sizeof(buff)));
            //Serial.printf("readBytes: %d\n", c);
            if (!c) {
              Serial.println("read timeout");
            }
            // write it to Serial
            //Serial.write(buff, c);
             unsigned int i; 
             int dh, dl;  // 16进制的高4位和低4位  
             unsigned char dest; 
             for(i=0;i<128;i=i+2)
             {        
              dest=(getNum(buff[i]) << 4) + getNum(buff[i+1]);
              Epaper_Write_Data(dest);
             }
            if (len > 0) {
              len -= c;
            }
          }
          
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }

      http.end();
    } else {
      Serial.printf("[HTTP} Unable to connect\n");
    }
  }
}
//////////////////////////////////END//////////////////////////////////////////////////